using System;
using System.Web.Caching;
using System.Configuration;
using System.Net.Mail;
using System.Data;
using System.Runtime.InteropServices;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;
using System.Xml.Serialization;
using System.DirectoryServices;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.Security;
using System.Security;
using System.Security.Policy;
using System.Security.Principal;
using System.Security.Permissions;
using EAT.Common;

namespace EAT.ExternalUserApproval
{
    [Guid("022239D3-1C2C-4814-AE72-AF4AAC4E387F")]
    public class ExternalUserApproval : System.Web.UI.WebControls.WebParts.WebPart
    {
        [DllImport("advapi32.dll")]
        static extern bool RevertToSelf();

        cUserManager UM;
        SqlManager SqlM;

        WebPartTable WPT;
        Label TextLabel;

        string[] ColumnNames;

        //
        // INDEX provides indices for the columns of the DataTable.
        //
        enum INDEX
        {
            USER = 0,
            REQUESTER,
            Max
        }

        public ExternalUserApproval()
        {
            this.ExportMode = WebPartExportMode.All;
        }

        protected override void OnLoad(EventArgs e)
        {
            UM = new cUserManager(ConfigurationManager.ConnectionStrings["ADAMConnectionString"].ConnectionString);
            SqlM = new SqlManager();
            TextLabel = new Label();
            WPT = new WebPartTable("EUA");
            ColumnNames = new string[(int)INDEX.Max];

            ColumnNames[(int)INDEX.USER] = Resources.userToBeProvisionedText;
            ColumnNames[(int)INDEX.REQUESTER] = Resources.requesterText;

            string mailMsg = null;
            string Password = null;
            string resultString = null;
            string eventArg = null;
            string[] Params;
            string tag = null;
            string action = null;
            string user = null;
            string requester = null;

            if (Page.IsPostBack)
            {
                eventArg = Page.Request["__EVENTARGUMENT"];

                if (eventArg.Length > 0)
                {
                    Params = eventArg.Split(",".ToCharArray());
                    tag = null;
                    action = null;
                    user = null;
                    requester = null;

                    //
                    // The postback should always contain a tag and action.
                    //

                    if (Params.Length > 1)
                    {
                        tag = Params[0];
                        action = Params[1];

                        if (tag == WPT.GetTag())
                        {
                            switch (action)
                            {
                                case "approve":
                                    {
                                        if (Params.Length == 4 && IsApprover())
                                        {
                                            user = HttpUtility.HtmlEncode(Params[2]);
                                            requester = HttpUtility.HtmlEncode(Params[3]);
                                            if (UM.IsValidUsername(user))
                                            {
                                                if (ApproveOrDenyUser(
                                                        true,
                                                        user,
                                                        ref Password,
                                                        ref resultString
                                                        ))
                                                {
                                                    mailMsg = string.Format(Resources.approvedUserEmailBodyText, user, Password);

                                                    TextLabel.Text += string.Format(Resources.approvedUserLabelText, user);
                                                    //
                                                    // Mark the user as possessing a generated password.
                                                    //
                                                    UM.SetPwdGenerated(user);
                                                }
                                                else
                                                {
                                                    TextLabel.Text += resultString;
                                                }
                                            }
                                        }
                                        break;
                                    }
                                case "deny":
                                    {
                                        if (Params.Length == 4 && IsApprover())
                                        {
                                            user = HttpUtility.HtmlEncode(Params[2]);
                                            requester = HttpUtility.HtmlEncode(Params[3]);

                                            if (UM.IsValidUsername(user))
                                            {
                                                if (ApproveOrDenyUser(
                                                        false,
                                                        user,
                                                        ref Password,
                                                        ref resultString
                                                        ))
                                                {
                                                    mailMsg = string.Format(Resources.deniedUserEmailBodyText, user, Context.User.Identity.Name);

                                                    TextLabel.Text += string.Format(Resources.deniedUserLabelText, user);
                                                }
                                            }
                                        }
                                        break;
                                    }
                                case "sort":
                                    {
                                        if (Params.Length == 4)
                                        {
                                            //
                                            // The column and direction are read from the URL.
                                            //
                                            WPT.SetSortColumn(Params[2]);
                                            WPT.SetSortOrder(Params[3]);
                                        }
                                        break;
                                    }
                                default:
                                    {
                                        break;
                                    }
                            }
                        }
                    }

                    if (mailMsg != null)
                    {
                        try
                        {
                            SPWeb web = SPControl.GetContextWeb(Context);
                            SPUser currentUser = web.CurrentUser;

                            MailMessage msg = new MailMessage();
                            msg.To.Add(new MailAddress(requester));
                            msg.Subject = Resources.provisioningEmailSubjectText;
                            msg.From = new MailAddress(SqlM.GetEntry("Config", "eMailSource"));

                            msg.Body = mailMsg;
                            SmtpClient client = new SmtpClient(SqlM.GetEntry("Config", "SMTPHost"));
                            client.Send(msg);
                        }
                        catch (Exception ex)
                        {
                            TextLabel.Text += "<br>" + ex.Message;
                        }
                    }
                }
            }
            else
            {
                base.OnLoad(e);
            }

            ConstructPendingUserTable();
        }

        //
        // ConstructPendingUserTable
        // Arguments - none.
        // Description:
        //      Build the SiteTable.  Key off of the URL.  Add columns for owner, 
        //      description, title, requester, and workflow status.  Query SQL and 
        //      Sharepoint to populate the table.
        //
        protected void ConstructPendingUserTable()
        {
            DataColumn[] key;
            DataColumn dc;

            key = new DataColumn[1];
            key[0] = new DataColumn(
                             Resources.userColumnHeaderText, 
                             typeof(String)
                             );
            WPT.GetTable().Columns.Add(key[0]);
            WPT.GetTable().PrimaryKey = key;

            dc = new DataColumn(
                         Resources.requesterColumnHeaderText,
                         typeof(String)
                         );

            WPT.GetTable().Columns.Add(dc);

            UM.GetPendingUsers(
                WPT.GetTable()
                );
        }

        //
        // Render
        // Arguments:
        //      writer - HtmlTextWriter that outputs the controls.
        // Description:
        //      Render draws the webpart.
        //
        protected override void Render(HtmlTextWriter writer)
        {
            if (!IsApprover())
            {
                TextLabel.Text = Resources.noPermissionsText;
                return;
            }

            writer.Write("<table border=\"0\" width=\"100%\" style=\"ms-authoringcontrols\">");
            writer.Write(@"<tr class=""grid-header"" align=""left"" style=""color:White;background-color:#5D7B9D;font-weight:bold;"">");
            writer.Write(@"<th>" + Resources.actionColumnHeaderText + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.USER]) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.REQUESTER]) + "</th>");
            writer.Write("</tr>");

            string user;
            string requester;

            foreach (DataRow dr in WPT.GetSortedRows(null))
            {
                user = HttpUtility.HtmlEncode(dr[(int)INDEX.USER].ToString().Trim());
                requester = HttpUtility.HtmlEncode(dr[(int)INDEX.REQUESTER].ToString().Trim());

                writer.Write("<tr>");
                
                //
                // The first hyperlink is the approve tag with the information about 
                // the user to be approved.
                //
                string tag = @"<td><a href=""javascript:__doPostBack('__Page','";
                tag += WPT.GetTag() + ",approve," + user + "," + requester;
                tag += @"')"">" + Resources.approveVerbText + "</a> ";
                writer.Write(tag);

                //
                // The second hyperlink is the deny tag.
                //
                tag = @"<a href=""javascript:__doPostBack('__Page','";
                tag += WPT.GetTag() + ",deny," + user + "," + requester;
                tag += @"')"">" + Resources.denyVerbText + "</a></td>";
                writer.Write(tag);

                writer.Write("<td>" + user + "</td>");
                writer.Write("<td>" + requester + "</td>");
                writer.Write("</tr>");
            }
            
            foreach (Control c in this.Controls)
            {
                writer.Write("<tr><td colspan=3>");
                writer.Write(c.ID + " ");
                c.RenderControl(writer);
                writer.Write("</td></tr>");
            }
            writer.Write("</table>");
        }

        protected override void CreateChildControls()
        {
            this.Controls.Add(TextLabel);
        }

        //
        // ApproveOrDenyUser
        // Arguments:
        //      fApprove - Indicates if the user is to be approved.
        //      User - user name to act upon.
        //      Password - the user's password as a return parameter.
        //      Result - string indicating the state of the operation.
        // Description:
        //      This routine approves or denies a user, and returns the 
        //      password of the user.
        //
        public bool ApproveOrDenyUser(
                        bool fApprove,
                        string User, 
                        ref string Password,
                        ref string Result
                        )
        {
            bool bStatus = true;

            if (fApprove)
            {
                try
                {
                    
                    if (Approve(User))
                    {
                        //
                        // Generate a password to use for the new account.
                        //
                        MembershipUser u = Membership.GetUser(User);
                        Password = Membership.GeneratePassword(9, 2);
                        Result = string.Format(Resources.activateResultText, User);
                    }
                    
                }
                catch (Exception e)
                {
                    Result = e.Message;
                    return false;
                }
            }
            else
            {
                try
                {
                    if (Membership.DeleteUser(User))
                        Result = string.Format(Resources.deletedResultText, User);
                    else
                    {
                        Result = string.Format(Resources.deletionFailedResultText, User);
                        return false;
                    }
                    RemoveUserFromSites(User);
                }
                catch (Exception e)
                {
                    Result = e.Message;
                    return false;
                }
            }
            return (true);
        }
        
        //
        // Approve
        // Arguments:
        //      Path - path to the user store
        // Description:
        //      Reverts to the process context and sets the msDS-UserAccountDisabled
        //      attribute to false.
        //
        public bool Approve(string Username)
        {
            bool bStatus = true;

            try
            {
                UM.SetDisabledBit(Username, false);
            }
            catch (Exception Ex)
            {
                bStatus = false;
            }
            return bStatus;
        }

        //
        // RemoveUserFromSites
        // Arguments:
        //      User - user to remove from sites
        // Description:
        //      Reverts to the process context and enumerates all sites in the web app.  
        //      For each site, delete mention of the passed User.
        //
        private void RemoveUserFromSites(string User)
        {
            WindowsIdentity wi = null;
            bool bReverted = false;

            try
            {
                wi = WindowsIdentity.GetCurrent();
                RevertToSelf();
                bReverted = true;
                WindowsIdentity.GetCurrent().Impersonate();

                SPWeb web = SPControl.GetContextWeb(System.Web.HttpContext.Current);
                SPWebApplication spWebApp = SPWebApplication.Lookup(new Uri(web.Url));
                string FullName = Membership.Provider.Name + ":" + User;
                foreach (SPSite s in spWebApp.Sites)
                {
                    //
                    // Users contains explicitly permitted users.
                    //
                    foreach (SPUser u in s.RootWeb.Users)
                    {
                        if (User.ToLower() == u.Name.ToLower())
                        {
                            s.RootWeb.AllowUnsafeUpdates = true;
                            s.RootWeb.Users.Remove(FullName);
                            s.RootWeb.AllowUnsafeUpdates = false;
                            break;
                        }
                    }
                    s.RootWeb.Dispose();

                    //
                    // SiteUsers contains users granted access via groups.
                    //
                    foreach (SPUser u in s.RootWeb.SiteUsers)
                    {
                        if (User.ToLower() == u.Name.ToLower())
                        {
                            s.RootWeb.AllowUnsafeUpdates = true;
                            s.RootWeb.SiteUsers.Remove(FullName);
                            s.RootWeb.AllowUnsafeUpdates = false;
                            break;
                        }
                    }
                    s.RootWeb.Dispose();
                    s.Dispose();
                }
            }
            catch (Exception Ex)
            {
                TextLabel.Text += Ex.Message;
            }
            finally
            {
                if (bReverted && wi != null)
                {
                    wi.Impersonate();
                }
            }
        }


        //
        // IsApprover
        // Description: 
        //      Verifies the calling user is a member of the group listed
        //      as the UACWorkflowApprovers.
        //
        bool IsApprover()
        {
            return WPT.IsUserInConfigGroup(
                           SPControl.GetContextWeb(Context).CurrentUser, 
                           "UACWorkflowApprovers"
                           );
        }
    }
}
